package utils;

import java.util.ArrayList;
import java.util.List;

import limpo.CellUnit;

import processing.core.PApplet;
import processing.core.PVector;

public class CellMembranePhysics {

	/**
	 * Soft Body 
	 * by Ira Greenberg.  
	 * 
	 * Softbody dynamics simulation using curveVertex() and curveTightness().
	 */

	// center point
	float centerX = 0; 
	float centerY = 0;

	float radius = 45;
	float rotAngle = -90;
	float accelX; 
	float accelY;
	float springing = 0.0009f; 
	float damping = 0.98f;

	//corner nodes
	//	int nodes = 6;
	//	float nodeStartX[] = new float[nodes];
	//	float nodeStartY[] = new float[nodes];
	//	float nodeX[] = new float[nodes];
	//	float nodeY[] = new float[nodes];
	//	float angle[] = new float[nodes];
	//	float frequency[] = new float[nodes];
	int nodes;
	float nodeStartX[];
	float nodeStartY[];
	float nodeX[];
	float nodeY[];
	float angle[];
	float frequency[];

	PApplet main;
	List<PVector> points;
	CellUnit father;

	// soft-body dynamics
	float organicConstant = 1;

	public CellMembranePhysics(PApplet main, List<PVector> points, CellUnit cellUnit) {
		this.main = main;
		this.points = new ArrayList<PVector>();
		this.father = cellUnit;
		Utils.copyPoints(points, this.points);

		this.nodes = points.size();
		System.out.println("NODES: " + this.nodes);
		this.nodeStartX = new float[nodes];
		this.nodeStartY = new float[nodes];
		this.nodeX = new float[nodes];
		this.nodeY = new float[nodes];
		this.angle = new float[nodes];
		this.frequency = new float[nodes];

		//center shape in window
		//		centerX = main.width/2;
		//		centerY = main.height/2;
		PVector centralPoint = getCentralPoint(points);
		centerX = centralPoint.x;
		centerY = centralPoint.y;

		// iniitalize frequencies for corner nodes
		for (int i=0; i<nodes; i++) {
			frequency[i] = main.random(5, 12);
		}
		main.noStroke();
	}

	private PVector getCentralPoint(List<PVector> points){
		PVector result = null;
		float maxX = 0;
		float maxY = 0;
		float minX = 999;
		float minY = 999;
		for (PVector p : points) {
			float curX = p.x;
			float curY = p.y;
			if(curX > maxX){
				maxX = curX;
			}
			if(curX < minX){
				minX = curX;
			}
			if(curY > maxY){
				maxY = curY;
			}
			if(curY < minY){
				minY = curY;
			}
		}
		float tamX = maxX - minX;
		float tamY = maxY - minY;
		result = new PVector(minX + (tamX/2), minY + (tamY/2));
		return result;
	}

	public void drawMembrane() {
		loadLocations();
		drawShape();
		moveShape();
	}

	public void loadLocations() {
		populateNodeStart();
	}

	private void populateNodeStart() {

		for (int i = 0; i < nodes; i++) {
			PVector point = this.points.get(i);
			nodeStartX[i] = point.x;
			nodeStartY[i] = point.y;
		}

	}

	private float getCenterY() {
		return centerY;
	}

	private float getCenterX() {
		return centerX;
	}

	public void drawShape() {
		
		main.fill(father.color);
		main.noStroke();
		for (int i = 0; i < nodes; i++) {
			float random = main.random(10);
			main.ellipse(nodeX[i], nodeY[i], 2, 2);
		}
		// draw polygon
		main.curveTightness(organicConstant);
		main.fill(father.color);
		main.beginShape();
		for (int i = 0; i < nodes; i++) {
			main.curveVertex(nodeX[i], nodeY[i]);
		}
		for (int i = 0; i < nodes-1; i++) {
			main.curveVertex(nodeX[i], nodeY[i]);
		}
		main.endShape(PApplet.CLOSE);
	}

	public void moveShape() {
		//move center point
		float deltaX = main.mouseX-getCenterX();
		float deltaY = main.mouseY-getCenterY();

		//float deltaX = (father.lastLocation.x - father.location.x)*100;
		//float deltaY = (father.lastLocation.y - father.location.y)*100;
		
		//float deltaX = (father.location.x - father.lastLocation.x)*10;
		//float deltaY = (father.location.y - father.lastLocation.y)*10;
		
		// create springing effect
		deltaX = deltaX * springing;
		deltaY = deltaY * springing;
		accelX = accelX + deltaX;
		accelY = accelY + deltaY;
		accelX = father.velocity.x;
		accelY = father.velocity.y;

		// move predator's center
		centerX = getCenterX() + accelX;
		centerY = getCenterY() + accelY;

		// slow down springing
		accelX = accelX * damping;
		accelY = accelY * damping;

		// change curve tightness
		organicConstant = 1 - ((PApplet.abs(accelX)+PApplet.abs(accelY))*.1f);
		//System.out.println("Organic = " + organicConstant);
		//organicConstant = 3f;
		//organicConstant = father.organic;

		//move nodes
		for (int i = 0; i < nodes; i++) {
			nodeX[i] = nodeStartX[i] + PApplet.sin(PApplet.radians(angle[i])) * (accelX*2);
			nodeY[i] = nodeStartY[i] + PApplet.sin(PApplet.radians(angle[i])) * (accelY*2);
			angle[i] = angle[i] + frequency[i];
		}
	}

	static public void main(String args[]) {
		PApplet.main(new String[] { "--bgcolor=#FFFFFF", "utils.CellMembranePhysics" });
	}
}
